#!/usr/bin/env python
# vim:fileencoding=UTF-8:ts=4:sw=4:sta:et:sts=4:ai
from __future__ import (unicode_literals, division,
                        print_function)

__license__   = 'GPL v3'
__copyright__ = '2013, Ida Leter'
__copyright__ = '2011, Jim Miller'
__docformat__ = 'restructuredtext en'

from PyQt4.Qt import (QDialog, QTableWidget, QMessageBox, QVBoxLayout, QHBoxLayout, QGridLayout,
                      QPushButton, QProgressDialog, QString, QLabel, QCheckBox, QIcon, QTextCursor,
                      QTextEdit, QLineEdit, QInputDialog, QComboBox, QClipboard, QVariant,QApplication,
                      QProgressDialog, QTimer, QDialogButtonBox, QPixmap, Qt, QAbstractItemView )

from calibre.gui2 import error_dialog, warning_dialog, question_dialog, info_dialog
from calibre.gui2.dialogs.confirm_delete import confirm
import traceback

from calibre import confirm_config_name
from calibre.gui2 import dynamic

from calibre_plugins.astroph_plugin.astroph import adapters,exceptions
from calibre_plugins.astroph_plugin.astroph import base_writer as writers

OVERWRITE='Overwrite'
ADDNEW='Add New'
SKIP='Skip'

class DownloadDialog(QDialog):

    def __init__(self, gui, prefs, icon, do_user_config, start_downloads):
        QDialog.__init__(self, gui)
        self.gui = gui
        self.do_user_config = do_user_config
        self.start_downloads = start_downloads

        self.setMinimumWidth(300)
        self.l = QVBoxLayout()
        self.setLayout(self.l)

        self.setWindowTitle('Astro-ph')
        self.setWindowIcon(icon)

        self.l.addWidget(QLabel('Paper URL(s), one per line:'))
        self.url = QTextEdit(self)
        self.url.setToolTip('URLs for papers, one per line.')
        self.url.setLineWrapMode(QTextEdit.NoWrap)
        clipboard=self.get_urls_clip(prefs)
        self.url.setText(clipboard)
        self.l.addWidget(self.url)
        self.prefs=prefs

        self.asph_button = QPushButton(
            'Download Papers', self)
        self.asph_button.setToolTip('Start download(s).')
        self.asph_button.clicked.connect(self.asph)
        self.l.addWidget(self.asph_button)

        horz = QHBoxLayout()
        self.about_button = QPushButton('About', self)
        self.about_button.clicked.connect(self.about)
        horz.addWidget(self.about_button)
        self.conf_button = QPushButton(
                'Configure this plugin', self)
        self.conf_button.clicked.connect(self.config)
        horz.addWidget(self.conf_button)
        self.l.addLayout(horz)

        self.resize(self.sizeHint())
        
    def is_good_downloader_url(self,url):
        return adapters.getNormalPaperURL(url)
        
    def get_urls_clip(self,prefs):
        url_list = []
        if prefs['urlsfromclip'] == True:
            for url in unicode(QApplication.instance().clipboard().text()).split():
                if self.is_good_downloader_url(url):
                    url_list.append(url)
                    
        return "\n".join(url_list)

    def about(self):
        # Get the about text from a file inside the plugin zip file
        # The get_resources function is a builtin function defined for all your
        # plugin code. It loads files from the plugin zip file. It returns
        # the bytes from the specified file.
        #
        # Note that if you are loading more than one file, for performance, you
        # should pass a list of names to get_resources. In this case,
        # get_resources will return a dictionary mapping names to bytes. Names that
        # are not found in the zip file will not be in the returned dictionary.
        text = get_resources('about.txt')
        QMessageBox.about(self, 'About the Astro-ph Plugin',
                text.decode('utf-8'))

    def asph(self):
        options={'collision':self.prefs['collision']}
        self.start_downloads(unicode(self.url.toPlainText()),
                             options)
        self.hide()

    def config(self):
        self.do_user_config(parent=self)

class UserPassDialog(QDialog):
    '''
    Need to collect User/Pass for some sites.
    '''
    def __init__(self, gui, site, exception=None):
        QDialog.__init__(self, gui)
        self.gui = gui
        self.status=False

        self.l = QGridLayout()
        self.setLayout(self.l)

        if exception.passwdonly:
            self.setWindowTitle('Password')
            self.l.addWidget(QLabel("A password is required for this paper(%s)."%exception.url),0,0,1,2)
            # user isn't used, but it's easier to still have it for
            # post processing.
            self.user = FakeLineEdit()
        else:
            self.setWindowTitle('User/Password')
            self.l.addWidget(QLabel("%s requires you to login to download this paper."%site),0,0,1,2)
        
            self.l.addWidget(QLabel("User:"),1,0)
            self.user = QLineEdit(self)
            self.l.addWidget(self.user,1,1)
   
        self.l.addWidget(QLabel("Password:"),2,0)
        self.passwd = QLineEdit(self)
        self.passwd.setEchoMode(QLineEdit.Password)
        self.l.addWidget(self.passwd,2,1)
   
        self.ok_button = QPushButton('OK', self)
        self.ok_button.clicked.connect(self.ok)
        self.l.addWidget(self.ok_button,3,0)

        self.cancel_button = QPushButton('Cancel', self)
        self.cancel_button.clicked.connect(self.cancel)
        self.l.addWidget(self.cancel_button,3,1)

        self.resize(self.sizeHint())
        
    def ok(self):
        self.status=True
        self.hide()

    def cancel(self):
        self.status=False
        self.hide()

class LoopProgressDialog(QProgressDialog):
    '''
    ProgressDialog displayed while fetching metadata for each story.
    '''
    def __init__(self, gui,
                 book_list,
                 foreach_function,
                 finish_function,
                 init_label="Fetching metadata for papers...",
                 win_title="Downloading metadata for papers",
                 status_prefix="Fetched metadata for"):
        QProgressDialog.__init__(self,
                                 init_label,
                                 QString(), 0, len(book_list), gui)
        self.setWindowTitle(win_title)
        self.setMinimumWidth(500)
        self.gui = gui
        self.foreach_function = foreach_function
        self.finish_function = finish_function
        self.status_prefix = status_prefix
        self.i = 0
        self.book_list = book_list
        
        ## self.do_loop does QTimer.singleShot on self.do_loop also.
        ## A weird way to do a loop, but that was the example I had.
        QTimer.singleShot(0, self.do_loop)
        self.exec_()

    def updateStatus(self):
        self.setLabelText("%s %d of %d"%(self.status_prefix,self.i+1,len(self.book_list)))
        self.setValue(self.i+1)
        print(self.labelText())

    def do_loop(self):

        if self.i == 0:
            self.setValue(0)

        book = self.book_list[self.i]
        
        try:
            ## collision spec passed into getadapter by partial from asph_plugin
            ## no retval only if it exists, but collision is SKIP
            self.foreach_function(book)
            
        except NotGoingToDownload as d:
            book['good']=False
            book['comment']=unicode(d)
            book['icon'] = d.icon 
            book['status']= 'Skip'  

        except Exception as e:
            book['good']=False
            book['comment']=unicode(e)
            book['icon']='dialog_error.png'
            book['status'] = 'Error'
            print("Exception: %s:%s"%(book,unicode(e)))
            traceback.print_exc()
            
        self.updateStatus()
        self.i += 1
            
        if self.i >= len(self.book_list) or self.wasCanceled():
            return self.do_when_finished()
        else:
            QTimer.singleShot(0, self.do_loop)

    def do_when_finished(self):
        self.hide()
        self.gui = None        
        # Queues a job to process these books in the background.
        self.finish_function(self.book_list)

    def get_books(self):
        return self.books_table.get_books()

    def toggle(self, *args):
        dynamic[confirm_config_name(self.name)] = self.again.isChecked()
        
class NotGoingToDownload(Exception):
    def __init__(self,error,icon='dialog_error.png'):
        self.error=error
        self.icon=icon

    def __str__(self):
        return self.error